"""Small image helper: load and resize images using Pillow when available,
fall back to Tk PhotoImage for PNG/GIF. Returns a Tk-compatible image object
and ensures a reference is kept by the caller.
"""
import os
import io
import shutil
import time
import tkinter as tk

try:
    from PIL import Image, ImageTk
    _HAS_PIL = True
except Exception:
    Image = None
    ImageTk = None
    _HAS_PIL = False


def _resolve_image_path(path):
    """解析图片路径，将相对路径转换为包内绝对路径
    
    Args:
        path: 图片路径（相对或绝对）
    
    Returns:
        str: 解析后的绝对路径
    """
    if not path:
        return None
    
    # 如果是绝对路径，直接返回
    if os.path.isabs(path):
        return path
    
    # 如果是相对路径，基于包根目录解析
    # 获取当前文件的绝对路径
    current_file = os.path.abspath(__file__)
    # 从 core/utils/image_utils.py 回到 alibaba 包根目录
    package_root = os.path.dirname(os.path.dirname(os.path.dirname(current_file)))
    # 拼接路径
    return os.path.join(package_root, path)


def load_thumbnail(path, size=(90, 90)):
    """Load an image from disk and return a Tk image object suitable for
    use in labels/canvases. If Pillow is available, it will be used to open
    and resize (preserving aspect). Otherwise, try tk.PhotoImage for
    supported formats (PNG/GIF). On failure, returns None.

    path: str path to image file
    size: (width, height) tuple
    returns: PhotoImage or ImageTk.PhotoImage or None
    """
    # 解析路径
    resolved_path = _resolve_image_path(path)
    if not resolved_path or not os.path.exists(resolved_path):
        return None

    if _HAS_PIL:
        try:
            img = Image.open(resolved_path)
            img.thumbnail(size, Image.LANCZOS)
            tk_img = ImageTk.PhotoImage(img)
            return tk_img
        except Exception:
            return None
    else:
        try:
            # PhotoImage supports GIF/PNG; if file is a supported format, this will work
            tk_img = tk.PhotoImage(file=resolved_path)
            return tk_img
        except Exception:
            return None


def load_circular_thumbnail(path, size=(90, 90)):
    """Load an image and return a circular-cropped Tk image (ImageTk.PhotoImage).

    The function will:
    - open the image with Pillow (if available),
    - center-crop the image to a square using the center of the original image,
    - resize to `size` (width, height) preserving high quality,
    - apply a circular mask so the returned image has transparent corners (RGBA),
    - convert to ImageTk.PhotoImage and return it.

    If Pillow is not available or any error occurs, falls back to `load_thumbnail`.
    """
    # 解析路径
    resolved_path = _resolve_image_path(path)
    if not resolved_path or not os.path.exists(resolved_path):
        return None

    if not _HAS_PIL:
        # Can't produce circular images without Pillow; fall back
        return load_thumbnail(resolved_path, size=size)

    try:
        img = Image.open(resolved_path).convert('RGBA')

        # center-crop to square based on the shorter side
        w, h = img.size
        side = min(w, h)
        left = (w - side) // 2
        top = (h - side) // 2
        right = left + side
        bottom = top + side
        img = img.crop((left, top, right, bottom))

        # resize to target size (may be non-square but we expect square)
        target_w, target_h = size
        # ensure we resize to exactly target size
        img = img.resize((target_w, target_h), Image.LANCZOS)

        # create circular mask
        mask = Image.new('L', (target_w, target_h), 0)
        draw = Image.new('L', (target_w, target_h), 0)
        from PIL import ImageDraw
        ImageDraw.Draw(mask).ellipse((0, 0, target_w, target_h), fill=255)

        # apply mask to alpha channel
        img.putalpha(mask)

        tk_img = ImageTk.PhotoImage(img)
        return tk_img
    except Exception:
        # fallback to non-circular thumbnail on any error
        return load_thumbnail(resolved_path, size=size)


def copy_product_image(source_path, product_id, target_dir="data/product_images"):
    """Copy and rename a product image file to the product images directory.
    
    Args:
        source_path: Path to the source image file
        product_id: Product ID to use in the filename
        target_dir: Directory to store the product images (default: data/product_images)
    
    Returns:
        str: Path to the copied image file, or None if failed
    
    Raises:
        ValueError: If source file doesn't exist or is not a valid image
    """
    if not source_path or not os.path.exists(source_path):
        raise ValueError(f"Source file does not exist: {source_path}")
    
    # Validate image format if PIL is available
    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
    source_ext = os.path.splitext(source_path)[1].lower()
    
    if source_ext not in valid_extensions:
        raise ValueError(f"Invalid image format. Supported formats: {', '.join(valid_extensions)}")
    
    if _HAS_PIL:
        # Verify it's a valid image file
        try:
            Image.open(source_path).verify()
        except Exception as e:
            raise ValueError(f"Invalid image file: {str(e)}")
    
    # Create target directory if it doesn't exist
    os.makedirs(target_dir, exist_ok=True)
    
    # Generate unique filename with timestamp
    timestamp = int(time.time() * 1000)  # milliseconds
    target_filename = f"product_{product_id}_{timestamp}{source_ext}"
    target_path = os.path.join(target_dir, target_filename)
    
    # Copy the file
    try:
        shutil.copy2(source_path, target_path)
        return target_path
    except Exception as e:
        raise RuntimeError(f"Failed to copy image file: {str(e)}")


def delete_product_image(image_path):
    """Delete a product image file.
    
    Args:
        image_path: Path to the image file to delete
    
    Returns:
        bool: True if deleted successfully, False otherwise
    """
    if not image_path or not os.path.exists(image_path):
        return False
    
    try:
        os.remove(image_path)
        return True
    except Exception as e:
        return False


def copy_review_image(source_path, target_dir="data/review_images"):
    """Copy and save a review image file.
    
    Args:
        source_path: Path to the source image file
        target_dir: Directory to store the review images (default: data/review_images)
    
    Returns:
        str: Relative path to the copied image file (relative to package root), or None if failed
    
    Raises:
        ValueError: If source file doesn't exist or is not a valid image
        ValueError: If image file size exceeds 5MB
    """
    if not source_path or not os.path.exists(source_path):
        raise ValueError(f"Source file does not exist: {source_path}")
    
    # Check file size (max 5MB)
    file_size = os.path.getsize(source_path)
    max_size = 5 * 1024 * 1024  # 5MB
    if file_size > max_size:
        raise ValueError(f"Image file size exceeds 5MB limit")
    
    # Validate image format
    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
    source_ext = os.path.splitext(source_path)[1].lower()
    
    if source_ext not in valid_extensions:
        raise ValueError(f"Invalid image format. Supported formats: {', '.join(valid_extensions)}")
    
    if _HAS_PIL:
        # Verify it's a valid image file
        try:
            Image.open(source_path).verify()
        except Exception as e:
            raise ValueError(f"Invalid image file: {str(e)}")
    
    # Resolve target directory to absolute path if it's relative
    if not os.path.isabs(target_dir):
        # Get package root directory (same as _resolve_image_path logic)
        current_file = os.path.abspath(__file__)
        package_root = os.path.dirname(os.path.dirname(os.path.dirname(current_file)))
        target_dir = os.path.join(package_root, target_dir)
    
    # Create target directory if it doesn't exist
    os.makedirs(target_dir, exist_ok=True)
    
    # Generate unique filename with timestamp
    timestamp = int(time.time() * 1000)  # milliseconds
    target_filename = f"review_{timestamp}{source_ext}"
    target_path = os.path.join(target_dir, target_filename)
    
    # Copy the file
    try:
        shutil.copy2(source_path, target_path)
        # Return relative path from package root
        package_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        rel_path = os.path.relpath(target_path, package_root)
        # Normalize path separators to forward slashes for consistency
        rel_path = rel_path.replace('\\', '/')
        return rel_path
    except Exception as e:
        raise RuntimeError(f"Failed to copy review image file: {str(e)}")


def delete_review_image(image_path):
    """Delete a review image file.
    
    Args:
        image_path: Path to the image file to delete
    
    Returns:
        bool: True if deleted successfully, False otherwise
    """
    if not image_path or not os.path.exists(image_path):
        return False
    
    try:
        os.remove(image_path)
        return True
    except Exception as e:
        return False


def validate_image_file(image_path, max_size_mb=5):
    """Validate an image file.
    
    Args:
        image_path: Path to the image file
        max_size_mb: Maximum file size in MB (default: 5)
    
    Returns:
        tuple: (is_valid, error_message)
    """
    if not image_path or not os.path.exists(image_path):
        return False, "File does not exist"
    
    # Check file size
    file_size = os.path.getsize(image_path)
    max_size = max_size_mb * 1024 * 1024
    if file_size > max_size:
        return False, f"File size exceeds {max_size_mb}MB limit"
    
    # Validate extension
    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
    _, ext = os.path.splitext(image_path)
    if ext.lower() not in valid_extensions:
        return False, f"Invalid image format. Supported formats: {', '.join(valid_extensions)}"
    
    # Validate image file if PIL is available
    if _HAS_PIL:
        try:
            Image.open(image_path).verify()
        except Exception as e:
            return False, f"Invalid image file: {str(e)}"
    
    return True, ""